package com.atguigu.gulimall.auth.controller;

import com.atguigu.common.constant.AuthConstant;
import com.atguigu.common.exception.BizErrorCode;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberResVo;
import com.atguigu.gulimall.auth.feign.MemberFeignService;
import com.atguigu.gulimall.auth.feign.ThirdPartyFeignService;
import com.atguigu.gulimall.auth.vo.UserLoginVo;
import com.atguigu.gulimall.auth.vo.UserRegisterVo;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Controller
@Slf4j
@RequestMapping("/auth/login")
public class LoginController {

    @Resource
    private ThirdPartyFeignService thirdPartyFeignService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private MemberFeignService memberFeignService;

    @Controller
    public static class InnerController {

        @GetMapping("/login.html")
        public String nestedEndpoint(HttpSession httpSession) {
            Object loginUser = httpSession.getAttribute(AuthConstant.LOGIN_USER);
            if (loginUser != null) {
                // 说明已经登录
                return "redirect:http://gulimall.com";
            }
            // 处理内部控制器方法逻辑
            return "login";
        }
    }


    @PostMapping("/")
    public String login(UserLoginVo vo, RedirectAttributes redirectAttributes, HttpSession httpSession) {

        R login = memberFeignService.login(vo);
        if (login.isOk()) {
            log.info("登录成功！！！");
            httpSession.setAttribute(AuthConstant.LOGIN_USER, login.getData(new TypeReference<MemberResVo>() {
            }));
            return "redirect:http://gulimall.com";
        }
        String message = login.getMessage();
        redirectAttributes.addFlashAttribute("error", Collections.singletonMap("msg", message));
        // 登录失败返回到登录页
        log.info("登录失败！！！");
        return "redirect:http://auth.gulimall.com/login.html";
    }

    @GetMapping("/sms/sendcode")
    @ResponseBody
    public R sendSmsCode(@RequestParam("phone") String phone) {

        String cacheName = AuthConstant.SMS_CODE_REGISTER_CACHE_PREFIX + phone;

        // 1.获取redis 缓存中数据 ,存在的话，判断时间，不存在直接放行
        String cacheCode = stringRedisTemplate.opsForValue().get(cacheName);
        if (!StringUtils.isEmpty(cacheCode)) {

            long cacheTms = Long.parseLong(cacheCode.split("_")[1]);
            if (System.currentTimeMillis() - cacheTms < 60_000) {
                // 60秒内重复发送验证码
                return R.error(BizErrorCode.SMS_IN_HIGH_FREQUENCY_ERROR);
            }
        }
        // 2. 加工6位验证码
        String code = UUID.randomUUID().toString().replace("-", "").substring(0, 6);

        // 3. 发送验证码
        thirdPartyFeignService.sendSmsCode(phone, code);
        // 4. 保存带有过期时间的验证码数据到redis
        stringRedisTemplate.opsForValue().set(cacheName, code + "_" + System.currentTimeMillis(), 5, TimeUnit.MINUTES);

        return R.ok();
    }

    @PostMapping("/register")
    public String register(@Validated UserRegisterVo vo, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
        if (bindingResult.hasErrors()) {
//            Map<String, String> error = bindingResult.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));

            HashMap<String, String> errInfo = new HashMap<>();
            bindingResult.getFieldErrors().forEach(e -> errInfo.put(e.getField(), e.getDefaultMessage()));
            redirectAttributes.addFlashAttribute("error", errInfo);

            // forward方式：会继承当前方法的请求方式，默认路径映射方式是以 get 方式请求的
            // 重定向到注册页，避免表单重复提交
            return "redirect:http://auth.gulimall.com/register.html";
        }

        // 真正的校验逻辑
        // 校验验证码
        String cacheName = AuthConstant.SMS_CODE_REGISTER_CACHE_PREFIX + vo.getPhone();
        String cacheCode = stringRedisTemplate.opsForValue().get(cacheName);
        if (!StringUtils.isEmpty(cacheCode)) {
            String code = cacheCode.split("_")[0];
            if (vo.getCode().equals(code)) {
                // 说明验证码正确
                // 继续向下验证用户名和手机号
                R r = memberFeignService.register(vo);
                if (r.isOk()) {
                    stringRedisTemplate.delete(cacheName);
                    return "redirect:http://auth.gulimall.com/login.html";
                } else {
                    // 说明用户名或者手机号 不对劲，此时不应该删除验证码
                    String message = r.getMessage();
                    redirectAttributes.addFlashAttribute("error", Collections.singletonMap("msg", message));
                }
            } else {
                redirectAttributes.addFlashAttribute("error", Collections.singletonMap("code", "验证码不正确"));
            }
        } else {
            redirectAttributes.addFlashAttribute("error", Collections.singletonMap("code", "验证码已过期/无效验证码"));
        }
        return "redirect:http://auth.gulimall.com/register.html";
    }

}
